﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace FolderHierarchy
{
    class SystemCalls
    {
        private static ImageList smallImageList;
        private static Dictionary<string, int> loadImageDictionary;

        [DllImport("shell32.dll")]
        static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);
        [DllImport("shell32.dll")]
        static extern IntPtr SHGetFileInfo(string pszPath, FILE_ATTRIBUTE dwFileAttributes, ref SHFILEINFO sfi, int cbFileInfo, SHGFI uFlags);

        static SystemCalls()
        {
            loadImageDictionary = new Dictionary<string, int>();
            smallImageList = new ImageList();
            smallImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
            addForderIcon();
        }

        public static void showProperties(string filePath)
        {
            SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
            info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info);
            info.lpVerb = "properties";
            info.lpFile = filePath;
            info.nShow = 5;// SW_SHOW;
            info.fMask = 12;// SEE_MASK_INVOKEIDLIST;
            ShellExecuteEx(ref info);
        }

        private static Icon GetIcon(string path, FILE_ATTRIBUTE dwAttr, SHGFI dwFlag)
        {
            SHFILEINFO fi = new SHFILEINFO();
            Icon ic = null;
            int iTotal = (int)SHGetFileInfo(path, dwAttr, ref fi, 0, dwFlag);
            ic = Icon.FromHandle(fi.hIcon);
            return ic;
        }

        private static void addFileIcon(string fileName)
        {
            smallImageList.Images.Add(GetIcon(fileName, FILE_ATTRIBUTE.NORMAL, SHGFI.USEFILEATTRIBUTES | SHGFI.ICON | SHGFI.LARGEICON));
        }
        private static void addForderIcon()
        {
            smallImageList.Images.Add(GetIcon("dic", FILE_ATTRIBUTE.DIRECTORY, SHGFI.USEFILEATTRIBUTES | SHGFI.ICON | SHGFI.LARGEICON));
        }

        public static ImageList getSmallImageList()
        {
            return smallImageList;
        }

        public static int getImageIndex(string fileName)
        {
            string ext = " ";
            int index = 0;
            int extIndex = fileName.Substring(fileName.LastIndexOf('\\')).LastIndexOf('.');
            //if (Directory.Exists(fileName))
            //{
            //    throw new InvalidProgramException();
            //}
            //else//文件图标索引获取
            {
                if (extIndex >= 0)
                    ext = fileName.Substring(fileName.LastIndexOf('.'));
                //判断该扩展名的文件图标是否已装载到imageList中
                if (!loadImageDictionary.TryGetValue(ext, out index))
                {
                    addFileIcon(ext);//装载图标到ImageList中
                    loadImageDictionary.Add(ext, smallImageList.Images.Count - 1);
                    index = smallImageList.Images.Count - 1;
                }
            }
            return index;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct SHELLEXECUTEINFO
        {
            public int cbSize;
            public uint fMask;
            public IntPtr hwnd;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpVerb;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpFile;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpParameters;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpDirectory;
            public int nShow;
            public IntPtr hInstApp;
            public IntPtr lpIDList;
            [MarshalAs(UnmanagedType.LPStr)]
            public string lpClass;
            public IntPtr hkeyClass;
            public uint dwHotKey;
            public IntPtr hIcon;
            public IntPtr hProcess;
        }
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public IntPtr iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        }
        public enum SHGFI : uint
        {
            ADDOVERLAYS = 0x20,
            ATTR_SPECIFIED = 0x20000,
            ATTRIBUTES = 0x800,
            DISPLAYNAME = 0x200,
            EXETYPE = 0x2000,
            ICON = 0x100,
            ICONLOCATION = 0x1000,
            LARGEICON = 0,
            LINKOVERLAY = 0x8000,
            OPENICON = 2,
            OVERLAYINDEX = 0x40,
            PIDL = 8,
            SELECTED = 0x10000,
            SHELLICONSIZE = 4,
            SMALLICON = 1,
            SYSICONINDEX = 0x4000,
            TYPENAME = 0x400,
            USEFILEATTRIBUTES = 0x10
        }
        public enum FILE_ATTRIBUTE
        {
            READONLY = 0x00000001,
            HIDDEN = 0x00000002,
            SYSTEM = 0x00000004,
            DIRECTORY = 0x00000010,
            ARCHIVE = 0x00000020,
            DEVICE = 0x00000040,
            NORMAL = 0x00000080,
            TEMPORARY = 0x00000100,
            SPARSE_FILE = 0x00000200,
            REPARSE_POINT = 0x00000400,
            COMPRESSED = 0x00000800,
            OFFLINE = 0x00001000,
            NOT_CONTENT_INDEXED = 0x00002000,
            ENCRYPTED = 0x00004000
        }
    }
}
